Overview

In the previous two assignments, we obtained data associated with the study Cannabidiol inhibits SARS-CoV-2 replication through induction of the host ER stress and innate immune responses and conducted thresholded differential gene expression analysis. We obtained the dataset from GEO with ID GSE168797, associated with the study Cannabidiol inhibits SARS-COV-2 replication and promotes the host innate immune response published on Science Advances. Out of the total of 57832 genes, 13705 remained after removing low counts and genes with duplicate identifiers. The top terms associated with the upregulated genes returned from the thresholded analysis using g:profiler are response to endoplasmic reticulum stress, proteasomal protein catabolic process, ERAD (Endoplasmic-reticulum-associated protein degradation) pathway; the top terms associated with the downregulated genes are mitotic nuclear division, chromatin binding, cell cycle.

The authors hypothesized and concluded that cannabidiol inhibits SARS-CoV-2 replication by up-regulating the host IRE1α ribonuclease endoplasmic reticulum (ER) stress response and interferon signaling pathways.

In this assignment, we will further investigate differential gene expression and attempt to discover and learn more about the pathways involved in CBD’s suggested antiviral effect against SARS-CoV-2. In particular, we will use non-thresholded gene enrichment analysis to obtain a more diverse portfolio of differentially expressed genes. The results from non-thresholded analysis will also serve as comparison to the results from the previously done thresholded analysis. Ideally, the non-thresholded analysis results further strengthen the plausibility of our previous results and the authors’ hypothesis in the original publication. Using the results obtained from the non-thresholded analysis, we will create an enrichment map network and conduct further analysis using the network.

Import Packages

if (!requireNamespace("RCurl", quietly = TRUE))
  install.packages("RCurl")
library("RCurl")

if (!requireNamespace("reshape2", quietly = TRUE))
  install.package("reshape2")

if (!requireNamespace("RCy3", quietly = TRUE))
  BiocManager::install("RCy3")

# high-res figures
knitr::opts_chunk$set(dpi=600,fig.width=7)

Helper functions for obtaining the GMT files and running GSEA.

fileExists_wildcard <- function(pattern, dir) {
  # check if there is any file matching the pattern (regex)
  return(length(grep(pattern, list.files(dir))) > 0)
}

folderExists_wildcard <- function(pattern, dir) {
  # check if there is any file matching the pattern (regex)
  return(length(grep(pattern, list.dirs(dir, recursive = FALSE))) > 0)
}
run_gsea <- function(gsea_jar, rnk, gmx, nperm, max_termsize, min_termsize, out_dir, rpt_label) {
  command <- paste(
    gsea_jar, 
    "GSEAPreRanked -gmx", gmx, 
    "-rnk", rnk, 
    "-nperm", nperm, 
    "-set_max", max_termsize, 
    "-set_min", min_termsize, 
    "-out", out_dir,
    "-rpt_label", rpt_label,
    "> gsea_out.txt",
    sep = " ")
  if (!folderExists_wildcard(rpt_label, "gsea_out"))
    system(command)
  else
    print("GSEA results already exists; remove previous result or use a different job name to continue.")
}
getGMT <- function(src, pattern) {
  gmt_url <- src

  filenames = getURL(gmt_url)
  textConn = textConnection(filenames)
  contents = readLines(textConn)
  close(textConn)
  
  # filter out the filenames using the regex pattern
  rx = gregexpr(pattern, contents,
                perl = TRUE)
  
  gmt_file <- unlist(regmatches(contents, rx))
  
  # download the gmt file if there is no file with extension .gmt in the gmt folder
  if (!fileExists_wildcard(".gmt", "gmt"))
    download.file(paste(gmt_url, gmt_file, sep = ""), destfile = file.path(getwd(), "gmt", gmt_file))
}

Non-thresholded Gene Enrichment Analysis

Create Ranked List

To perform a non-thresholded gene enrichment analysis, we use GSEA. But before we do that, we first create a ranked list using the set of all differentially expressed genes obtained in Assignment 2.

diff_exp_lst

Recall that rank can be calculated using the following formula \[ \mathrm{rank} = \mathrm{sign}(\mathrm{logFC}) \cdot(-\log_{10}p) \]

# calculate ranks
ranks <- sign(diff_exp_lst$logFC) * -log10(diff_exp_lst$PValue)

# store the ranks along with gene names
rank_list_gene_names <- diff_exp_lst$hgnc_symbol
rank_list <- cbind(rank_list_gene_names, ranks)

# sort the ranked list
rank_list <- rank_list[order(as.numeric(rank_list[,2]), decreasing = TRUE), ]
colnames(rank_list) <- c("GeneName", "rank")

# store the ranked list
write.table(rank_list, file.path(getwd(), "CBD_vs_Veh_ranks.rnk"),
            col.names = TRUE, sep = "\t", row.names = FALSE, quote = FALSE)

kable(head(rank_list), caption = "Table 1: Top genes in the ranked list") %>% kableExtra::kable_styling("striped")
Table 1: Top genes in the ranked list
GeneName rank
DNAJB9 12.93030398338
IGFBP1 12.7474872887814
HSPA5 12.4494138867865
CRELD2 11.7308461237434
ADGRF4 11.5485864149102
GABARAPL1 11.5327022737292

Download Gene Sets

For this analysis, we will use the gene sets available at Bader’s Lab

getGMT(
  src = "http://download.baderlab.org/EM_Genesets/current_release/Human/symbol/",
  pattern = "(?<=<a href=\")(.*.GOBP_AllPathways_no_GO_iea.*.)(.gmt)(?=\">)"
)

The gene set we used for this analysis is “Human_GOBP_AllPathways_no_GO_iea_April_01_2022_symbol.gmt” from Bader’s lab. The “no_GO_iea” tag in the file name indicates that the gene set does not include genes inferred from electronic annotation.

Analysis using GSEA

Next, we run GSEA from the command line. Note that the GSEA jar is stored at “GSEA_4.2.4/”. If you have the GSEA jar stored at a different location, change the gsea_jar parameter to point to the correct location.

## function that reports that GSEA does not exists and terminate the knitting of the current notebook
reportGseaDNE <- function() {
  print("GSEA not found")
  knitr::knit_exit()
}
# check if GSEA directory exists
if (folderExists_wildcard("GSEA_*", "~")) {
  # get the GSEA installation (version independent)
  gsea_dir = list.dirs("~", recursive = FALSE)[grep("GSEA_*", list.dirs("~", recursive = FALSE))]
  if (length(gsea_dir) > 0) {
    gsea_path = file.path(gsea_dir[1], "gsea-cli.sh")
    # if the shell script exists, then execute GSEA command
    if (file.exists(gsea_path)) {
      run_gsea(
        gsea_jar = gsea_path,
        rnk = file.path(getwd(), "CBD_vs_Veh_ranks.rnk"),
        gmx = file.path(getwd(), "gmt", "Human_GOBP_AllPathways_no_GO_iea_April_01_2022_symbol.gmt"),
        nperm = 1000,
        max_termsize = 200,
        min_termsize = 15,
        out_dir = file.path(getwd(), "gsea_out"),
        rpt_label = "CBD_vs_Veh_GSEAAnalysis")
    }
    else
      reportGseaDNE()
  } else
    reportGseaDNE()
  
} else {
  reportGseaDNE()
}

After running the previous block successfully, we would have the GSEA result stored at the folder gsea_out/CBD_vs_Veh_VSEAAnalysis.GseaPreranked.xxx. We can pull the report for the positive and negative classes.

gsea_folder_names <- list.dirs("gsea_out", recursive = FALSE)[grepl("CBD_vs_Veh_GSEAAnalysis", list.dirs("gsea_out", recursive = FALSE))]
gsea_folder_name <- gsea_folder_names[1]
gsea_job_id <- tail(strsplit(gsea_folder_name, "\\.")[[1]], n = 1)

gsea_pos <- read.csv(file.path(gsea_folder_name, sprintf("gsea_report_for_na_pos_%s.tsv", gsea_job_id)), sep = "\t")
gsea_neg <- read.csv(file.path(gsea_folder_name, sprintf("gsea_report_for_na_neg_%s.tsv", gsea_job_id)), sep = "\t")

We would like to parse the rows in the GSEA report so that it is more readable.

# parse the NAME column in GSEA output (split by '%')
parseGseaName <- function(gsea_table) {
  splitted_names = reshape2::colsplit(gsea_table$NAME, '%', names = c("description", 'src', 'id'))
  return(cbind(gsea_table, splitted_names))
}

gsea_pos <- parseGseaName(gsea_pos)
gsea_neg <- parseGseaName(gsea_neg)

kable(head(gsea_pos[,c("description", "src", "SIZE", "NES", "ES")]), caption = "Table 2: Top terms of upregualted genes") %>% kableExtra::kable_styling("striped")
Table 2: Top terms of upregualted genes
description src SIZE NES ES
RESPONSE TO ENDOPLASMIC RETICULUM STRESS GOBP 85 3.725632 0.5870175
UNFOLDED PROTEIN RESPONSE (UPR) REACTOME 44 3.523760 0.6604784
IRE1ALPHA ACTIVATES CHAPERONES REACTOME 27 3.277616 0.6968865
ASPARAGINE N-LINKED GLYCOSYLATION REACTOME 104 3.171751 0.4745622
ERAD PATHWAY GOBP 48 3.165996 0.5732202
XBP1(S) ACTIVATES CHAPERONE GENES REACTOME 26 3.146467 0.6926015
kable(head(gsea_neg[,c("description", "src", "SIZE", "NES", "ES")]), caption = "Table 3: Top terms of downregulated genes") %>% kableExtra::kable_styling("striped")
Table 3: Top terms of downregulated genes
description src SIZE NES ES
NUCLEAR CHROMOSOME SEGREGATION GOBP 76 -5.127148 -0.7340092
CHROMOSOME SEGREGATION GOBP 89 -5.023200 -0.6817771
SISTER CHROMATID SEGREGATION GOBP 66 -4.972249 -0.7265686
MITOTIC CELL CYCLE PROCESS GOBP 186 -4.693581 -0.5358869
NUCLEAR DIVISION GOBP 92 -4.636481 -0.6301082
MITOTIC SISTER CHROMATID SEGREGATION GOBP 60 -4.625700 -0.7114142

We also present the enrichment plots for some of the top terms associated with the upregulated genes.

Figure 1: Enrichment plot for “UNFOLDED PROTEIN RESPONSE” from Reactome


Figure 2: Enrichment plot for “Response to ER stress” from GOBP

The top terms associated with the upregulated genes are all related to ER stress response and more interestingly, unfolded protein response. In particular, ERAD (ER assocaited protein degradation) pathway is also one of the top terms. Those pathways and mechanisms are also discussed in the literature. We will explore those pathway using network analysis in the next section.

Discussion

  1. For this analysis, I used GSEA version 4.2.3. I used the GSEA preranked analysis in GSEA. The geneset used was obtained from Bader’s lab’s repository. The code for obtaining the geneset is shown above. The geneset is created on April 1, 2022. The geneset is curated from GO, GOBP, MSigdb, Reactome, WikiPathways, NetPath, Panther, and HumanCyc.

  2. In the enrichment result, the positive phenotype are the samples treated with CBD, and the negative phenotype are the ones without CBD treatment. 1064 / 2059 gene sets are upregulated in the positive samples, and 995 / 2059 gene sets are upregulated in the negative samples. In the positive phenotype, 217 gene sets are significantly enriched at nominal pvalue < 1%; in the negative phenotype, 342 gene sets are significantly enriched at nominal pvalue < 1%. The top terms associated with the positive samples are: RESPONSE TO ENDOPLASMIC RETICULUM STRESS (GO), UNFOLDED PROTEIN RESPONSE (UPR) (Reactome), IRE1ALPHA ACTIVATES CHAPERONES (Reactome). The top terms associated with the negative samples are: NUCLEAR CHROMOSOME SEGREGATION, CHROMOSOME SEGREGATION, SISTER CHROMATID SEGREGATION, all from GOBP.

  3. The results from non-thresholded analysis using GSEA is very similar to the result obtained from the previous analysis using G:profiler. The upregulated genes are mostly related to ER stress response and protein degradation whereas the donwregulated genes are mostly related to cell cycle regulation and cell divisions. However, overall, the terms from the results using GSEA is more diverse. This is because GSEA is not a thresholded method and it gets to consider all genes instead of just those passed the threshold in thresholded methods. Although the top terms are mostly the same, this is not a straightforward comparison because the two methods (GSEA v.s. G:profiler) uses different approaches. The similarity in the the top terms is likely attributed to the significant overrepresentation of certain genes. This also gives us strong evidence to believe that the differentially expressed genes are more likely than not to be involved in these pathways.

Network Analysis Using Cytoscape

Creation of Enrichment Map

In this section, we will import the results from GSEA into Cytoscape and visualize the enrichment results as a network. To this end, we first need to create a network based on the enrichment result. We use the Cytoscape plugin EnrichmentMap, which can generate a network from GSEA outputs.

We created the enrichment map by using the Cytoscape GUI. We first imported the GSEA output for positive and negative phenotypes. Then, we imported the GMT file and ranked list file. Finally, we inspected and changed the parameters for Enrichment map. The thresholds for EnrichmentMap are as follows:

  • FDR q-value cutoff: 0.1
  • p-value cutoff: 0.05
  • Edge cutoff: 0.375
  • Edge filtering metric: Jaccard+Overlap combined
  • Parse baderlab names in GMT file: True (for better readability)

Recall that Jaccard metric measures the intersection over union whereas the overlap metric measures intersection over the minimum size.

The resulting network is shown below:

Figure 3: Enrichment map generated from GSEA result. Positive phenotypes (upregulated) are colored red and negative phenotypes (downregulated) are colored blue.

A zoomed in view of the cluster of terms associated with ER stress response and unfolded protein response. These are the clusters that we will further investigate.

Figure 4: A zoomed in view of the enrichment map showing the cluster containing terms and pathways that are associated with ER stress response and unfolded protein response. Those are the pathways the authors of the original paper proposed to be related to CBD’s role in inhibiting SARS-CoV-2 replication.

Figure 5: A zoomed in view of the enrichment map showing the cluster containing terms and pathways that are associated with interferon responses. The authors of the original publication mentioned that these pathways as an alternative mechanism of CBD’s inhibition of SARS-CoV-2 replication.

Network Annotation

Next, we annotated the network using the plugin AutoAnnotate. For AutoAnnoate, we used the default parameter: - Labeling algorithm: WordCloud Adjacent Word - Max word per label: 3 - Min word occurrence: 1 - Adjacent word bonus: 8

Additionally, we turned on the option “Layout network to prevent cluster overlap” so that the resulting annotated network is more clear and easy-to-read.

The resulting annotated network is shown below.

Figure 6: Annotated network of the original network shown in Figure 5. Clusters are re-layout to prevent overlap and improve readability.

Summary Network

We collapsed the annotated network into a summary network using the built-in feature provided by AutoAnnotate.

Figure 7: Summary network with the annotation clusters collapsed.

Figure 8: A zoomed in view of the center of the summary network. The highlighted nodes represent the main theme of the differentially expressed genes.

The major themes in the analysis are:

  • ER stress (upregulated)
  • Protein degradation (upregulated)
  • Immune response (upregulated)
  • Protein folding (upregulated)
  • Cell cycle (downregulated)
  • DNA repair (downregulated)

The upregulated pathways fit the model and agree with the results by the authors of the original publication. The authors did not mention too much about the negatively regulated pathways. They are not necessarily novel but nonetheless worth futher investigating.

Discussion

Discussion questioned answered in the previous subsections.

Publication-ready Figure

Figure 9: Publication-ready figure. (a) The entire enrichment map, generated using the EnrichmentMap plugin in Cytoscape; (b) A zoomed-in view of the enrichment map showing pathways relating to ER stress response and unfolded protein response; (c) A collapsed summary network; (d) A zoomed-in view of the summary network highlighting the major themes.

(Unfortunately, resolution of figures is a little bit low and the DPI option does not seem to work. Please refer to journal for higher resolution figures.)

Final Discussion

  1. The enrichment results suppor the conclusions and mechanism discussed in the original paper. The results do not differ significantly from those from Assignment 2.

  2. The involvement of the genes in ER stress response and the mechanism of unfolded protein response pathway are discussed extensively in (2008) Eizirik et al. and (2005) Credle et al. The mechanism discussed in these papers also agree with the proposed mechanism of CBD’s antiviral effect discussed by in the original paper and the results obtained in this analysis.

Analysis of UPR Pathway

We further investigate the unfolded protein response pathway. The pathway is of particular interest because the authors proposed this as the potential mechanism for the antiviral effect of CBD. This pathway is available on Reactome. Here is a detailed pathway diagram obtained from Reactome.

Figure 10: Pathway diagram for the Unfolded Protein Response pathway.

Export the normalized count file (with HGNC symbol annotation) for annotation on Reactome pathway diagram.

write.csv(normalized_counts_annot[3:14], file = "normalized_count_annotated.txt")
write.csv(qlf_diff_exp$table, file = "qlf_diff_exp.txt")

The expression data is uploaded to the online analysis tools provided by Reactome. Below is the resulting pathway diagram with the genes in the pathway colored based on their level of differential expression (log FC). As shown in the figure, the majority of genes in this pathway are upregulated although a handful are also downregulated. Unfortunately, the built-in tool in Reactome does not allow us to annotate the pathway with p-value or the acutal numerial logFC value.

Figure 11: Pathway diagram for the Unfolded Protein Response pathway with genes in the pathway color-coded to reflect the log fold change.

We repeat a similar analysis using Cytoscape. This time, we use the expression data obtained in A2. This file includes not only the logFC but also the p-values for each differentially expressed gene. After importing the Reactome pathway into Cytoscape, we write an automation script to annotate the network using logFC and p-values:

nodes <- RCy3::getAllNodes()
attrib_table <- RCy3::getTableColumns()
for (n in nodes) {
  npos = RCy3::getNodePosition(node.names = n)
  attrib = attrib_table[attrib_table$name == n,]
  if (!is.null(attrib$logFC)) {
    RCy3::addAnnotationText(text = sprintf("logFC = %.2f", attrib$logFC), x.pos = npos$x_location, y.pos = npos$y_location)
    RCy3::addAnnotationText(text = sprintf("p = %.2g", attrib$PValue), x.pos = npos$x_location, y.pos = npos$y_location + 12)
  }
}

This script was run outside the notebook. It is shown here for demonstration purpose only.

The final annoated network is annoted with logFC and p-values. The color of each node corresponds to log fold change (red = upregulated, blue = downregulated) and the size of each node is inverse proportional to the p-value of the gene represented by the node.

Figure 12: Annotated reactome pathway. The larger a node, the lower the p-value. Red corresponds to a high logFC value (upregulated) whereas blue corresponds to a low (negative) logFC value (downregulated).

As shown in the figure above, we can see the genes involved in the unfolded protein response pathway are mostly significantly upregulated. This is consistent with the finding in the original publication. The authors further confirmed this by observing the effect on SARS-CoV-2 infection in cells with the ERN1 gene (one of the gene involved in this pathway) knocked out. Their experiment shows reduced antiviral effects even with CBD treatment in ERN1 knockout cells.

Journal

Link to my journal entry for this assignment: https://github.com/bcb420-2022/Kevin_Gao/wiki/Assignment-3

Reference

Isserlin, R. (n.d.). Enrichment Map Analysis Pipeline. Bader Lab GitHub.

Kucera, M., Isserlin, R., Arkhangorodsky, A., & Bader, G. D. (2016). AutoAnnotate: A Cytoscape app for summarizing networks with Semantic Annotations. F1000Research, 5, 1717. https://doi.org/10.12688/f1000research.9090.1

Reimand, J., Isserlin, R., Voisin, V., Kucera, M., Tannus-Lopes, C., Rostamianfar, A., Wadi, L., Meyer, M., Wong, J., Xu, C., Merico, D., & Bader, G. D. (2019). Pathway enrichment analysis and visualization of OMICS data using G:Profiler, GSEA, Cytoscape and EnrichmentMap. Nature Protocols, 14(2), 482–517. https://doi.org/10.1038/s41596-018-0103-9

Chen Y, Lun ATL, Smyth GK (2016). From reads to genes to pathways: differential expression analysis of RNA-Seq experiments using Rsubread and the edgeR quasi-likelihood pipeline. F1000Research 5, 1438

Durinck, S., Spellman, P. T., Birney, E., & Huber, W. (2009). Mapping identifiers for the integration of genomic datasets with the R/Bioconductor package biomaRt. Nature - protocols, 4(8), 1184–1191. https://doi.org/10.1038/nprot.2009.97 Martin Morgan (2021). BiocManager: Access the Bioconductor Project Package Repository. R package version 1.30.16. https://CRAN.R-project.org/package=BiocManager

McCarthy DJ, Chen Y and Smyth GK (2012). Differential expression analysis of multifactor RNA-Seq experiments with respect to biological variation. Nucleic Acids Research 40, 4288-4297

Nguyen, L. C., Yang, D., Nicolaescu, V., Best, T. J., Ohtsuki, T., Chen, S.-N., Friesen, J. B., Drayman, N., Mohamed, A., Dann, C., Silva, D., Gula, H., Jones, K. A., Millis, J. M., Dickinson, B. C., Tay, S., Oakes, S. A., Pauli, G. F., Meltzer, D. O., … Rosner, M. R. (2021). Cannabidiol inhibits SARS-COV-2 replication and promotes the host innate immune response. Science Advances. https://www.science.org/doi/abs/10.1126/sciadv.abi6110 Robinson MD, McCarthy DJ and Smyth GK (2010). edgeR: a Bioconductor package for differential expression analysis of digital gene expression data. Bioinformatics 26, 139-140

Gu, Z. (2016) Complex heatmaps reveal patterns and correlations in multidimensional genomic data. Bioinformatics.

Kolberg L, Raudvere U, Kuzmin I, Vilo J, Peterson H (2020). “gprofiler2- an R package for gene list functional enrichment analysis and namespace conversion toolset g:Profiler.” F1000Research, 9 (ELIXIR)(709). R package version 0.2.1.

Stefan Milton Bache and Hadley Wickham (2020). magrittr: A Forward-Pipe Operator for R. https://magrittr.tidyverse.org, https://github.com/tidyverse/magrittr. van Breemen, R. B., Muchiri, R. N., Bates, T. A., Weinstein, J. B., Leier, H. C., Farley, S., & Tafesse, F. G. (2022).

Cannabinoids Block Cellular Entry of SARS-CoV-2 and the Emerging Variants. Journal of natural products, 85(1), 176–184. https://doi.org/10.1021/acs.jnatprod.1c00946

Fabregat A, Sidiropoulos K, Viteri G, Marin-Garcia P, Ping P, Stein L, D’Eustachio P, Hermjakob H. Reactome diagram viewer: data structures and strategies to boost performance. Bioinformatics (Oxford, England). 2018 Apr;34(7) 1208-1214. doi: 10.1093/bioinformatics/btx752. PubMed PMID: 29186351. PubMed Central PMCID: PMC6030826.

Eizirik, D. L., Cardozo, A. K., & Cnop, M. (2008). The role for endoplasmic reticulum stress in diabetes mellitus. Endocrine reviews, 29(1), 42–61. https://doi.org/10.1210/er.2007-0015

Credle, J. J., Finer-Moore, J. S., Papa, F. R., Stroud, R. M., & Walter, P. (2005). On the mechanism of sensing unfolded protein in the endoplasmic reticulum. Proceedings of the National Academy of Sciences of the United States of America, 102(52), 18773–18784. https://doi.org/10.1073/pnas.0509487102

LS0tCnRpdGxlOiAiS2V2aW4gR2FvIC0gQXNzaWdubWVudCAzOiBEYXRhc2V0IFBhdGh3YXkgYW5kIE5ldHdvcmsgQW5hbHlzaXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBtYXRoamF4OiAiaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbWF0aGpheC8yLjcuNy9NYXRoSmF4LmpzP2NvbmZpZz1UZVgtTU1MLUFNX0NIVE1MIgotLS0KCiMgT3ZlcnZpZXcKCmBgYHtyIGEyX3NvdXJjZSwgaW5jbHVkZT1GQUxTRSxlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpvcHRpb25zKHdhcm49LTEpCmEyX291dHB1dCA8LSBrbml0cjo6a25pdF9jaGlsZCgnYXNzaWdubWVudDIuUm1kJywgcXVpZXQgPSBUUlVFKQojIHJ1biB0aGUgZ2FyYmFnZSBjb2xsZWN0b3IKZ2MoKQpgYGAKCkluIHRoZSBwcmV2aW91cyB0d28gYXNzaWdubWVudHMsIHdlIG9idGFpbmVkIGRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdHVkeSAqKkNhbm5hYmlkaW9sIGluaGliaXRzIFNBUlMtQ29WLTIgcmVwbGljYXRpb24gdGhyb3VnaCBpbmR1Y3Rpb24gb2YgdGhlIGhvc3QgRVIgc3RyZXNzIGFuZCBpbm5hdGUgaW1tdW5lIHJlc3BvbnNlcyoqIGFuZCBjb25kdWN0ZWQgdGhyZXNob2xkZWQgZGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcy4gV2Ugb2J0YWluZWQgdGhlIGRhdGFzZXQgZnJvbSBHRU8gd2l0aCBJRCBHU0UxNjg3OTcsIGFzc29jaWF0ZWQgd2l0aCB0aGUgc3R1ZHkgQ2FubmFiaWRpb2wgaW5oaWJpdHMgU0FSUy1DT1YtMiByZXBsaWNhdGlvbiBhbmQgcHJvbW90ZXMgdGhlIGhvc3QgaW5uYXRlIGltbXVuZSByZXNwb25zZSBwdWJsaXNoZWQgb24gU2NpZW5jZSBBZHZhbmNlcy4gT3V0IG9mIHRoZSB0b3RhbCBvZiA1NzgzMiBnZW5lcywgMTM3MDUgcmVtYWluZWQgYWZ0ZXIgcmVtb3ZpbmcgbG93IGNvdW50cyBhbmQgZ2VuZXMgd2l0aCBkdXBsaWNhdGUgaWRlbnRpZmllcnMuIFRoZSB0b3AgdGVybXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB1cHJlZ3VsYXRlZCBnZW5lcyByZXR1cm5lZCBmcm9tIHRoZSB0aHJlc2hvbGRlZCBhbmFseXNpcyB1c2luZyBnOnByb2ZpbGVyIGFyZSByZXNwb25zZSB0byBlbmRvcGxhc21pYyByZXRpY3VsdW0gc3RyZXNzLCBwcm90ZWFzb21hbCBwcm90ZWluIGNhdGFib2xpYyBwcm9jZXNzLCBFUkFEIChFbmRvcGxhc21pYy1yZXRpY3VsdW0tYXNzb2NpYXRlZCBwcm90ZWluIGRlZ3JhZGF0aW9uKSBwYXRod2F5OyB0aGUgdG9wIHRlcm1zIGFzc29jaWF0ZWQgd2l0aCB0aGUgZG93bnJlZ3VsYXRlZCBnZW5lcyBhcmUgbWl0b3RpYyBudWNsZWFyIGRpdmlzaW9uLCBjaHJvbWF0aW4gYmluZGluZywgY2VsbCBjeWNsZS4KClRoZSBhdXRob3JzIGh5cG90aGVzaXplZCBhbmQgY29uY2x1ZGVkIHRoYXQgY2FubmFiaWRpb2wgaW5oaWJpdHMgU0FSUy1Db1YtMiByZXBsaWNhdGlvbiBieSB1cC1yZWd1bGF0aW5nIHRoZSBob3N0IElSRTHOsSByaWJvbnVjbGVhc2UgZW5kb3BsYXNtaWMgcmV0aWN1bHVtIChFUikgc3RyZXNzIHJlc3BvbnNlIGFuZCBpbnRlcmZlcm9uIHNpZ25hbGluZyBwYXRod2F5cy4KCkluIHRoaXMgYXNzaWdubWVudCwgd2Ugd2lsbCBmdXJ0aGVyIGludmVzdGlnYXRlIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5kIGF0dGVtcHQgdG8gZGlzY292ZXIgYW5kIGxlYXJuIG1vcmUgYWJvdXQgdGhlIHBhdGh3YXlzIGludm9sdmVkIGluIENCRCdzIHN1Z2dlc3RlZCBhbnRpdmlyYWwgZWZmZWN0IGFnYWluc3QgU0FSUy1Db1YtMi4gSW4gcGFydGljdWxhciwgd2Ugd2lsbCB1c2Ugbm9uLXRocmVzaG9sZGVkIGdlbmUgZW5yaWNobWVudCBhbmFseXNpcyB0byBvYnRhaW4gYSBtb3JlIGRpdmVyc2UgcG9ydGZvbGlvIG9mIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcy4gVGhlIHJlc3VsdHMgZnJvbSBub24tdGhyZXNob2xkZWQgYW5hbHlzaXMgd2lsbCBhbHNvIHNlcnZlIGFzIGNvbXBhcmlzb24gdG8gdGhlIHJlc3VsdHMgZnJvbSB0aGUgcHJldmlvdXNseSBkb25lIHRocmVzaG9sZGVkIGFuYWx5c2lzLiBJZGVhbGx5LCB0aGUgbm9uLXRocmVzaG9sZGVkIGFuYWx5c2lzIHJlc3VsdHMgZnVydGhlciBzdHJlbmd0aGVuIHRoZSBwbGF1c2liaWxpdHkgb2Ygb3VyIHByZXZpb3VzIHJlc3VsdHMgYW5kIHRoZSBhdXRob3JzJyBoeXBvdGhlc2lzIGluIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbi4gVXNpbmcgdGhlIHJlc3VsdHMgb2J0YWluZWQgZnJvbSB0aGUgbm9uLXRocmVzaG9sZGVkIGFuYWx5c2lzLCB3ZSB3aWxsIGNyZWF0ZSBhbiBlbnJpY2htZW50IG1hcCBuZXR3b3JrIGFuZCBjb25kdWN0IGZ1cnRoZXIgYW5hbHlzaXMgdXNpbmcgdGhlIG5ldHdvcmsuCgojIyBJbXBvcnQgUGFja2FnZXMKCmBgYHtyIGEzX2ltcG9ydH0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJSQ3VybCIsIHF1aWV0bHkgPSBUUlVFKSkKICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIpCmxpYnJhcnkoIlJDdXJsIikKCmlmICghcmVxdWlyZU5hbWVzcGFjZSgicmVzaGFwZTIiLCBxdWlldGx5ID0gVFJVRSkpCiAgaW5zdGFsbC5wYWNrYWdlKCJyZXNoYXBlMiIpCgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIlJDeTMiLCBxdWlldGx5ID0gVFJVRSkpCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoIlJDeTMiKQoKIyBoaWdoLXJlcyBmaWd1cmVzCmtuaXRyOjpvcHRzX2NodW5rJHNldChkcGk9NjAwLGZpZy53aWR0aD03KQpgYGAKCkhlbHBlciBmdW5jdGlvbnMgZm9yIG9idGFpbmluZyB0aGUgR01UIGZpbGVzIGFuZCBydW5uaW5nIEdTRUEuCgpgYGB7ciBmaWxlX2hlbHBlcn0KZmlsZUV4aXN0c193aWxkY2FyZCA8LSBmdW5jdGlvbihwYXR0ZXJuLCBkaXIpIHsKICAjIGNoZWNrIGlmIHRoZXJlIGlzIGFueSBmaWxlIG1hdGNoaW5nIHRoZSBwYXR0ZXJuIChyZWdleCkKICByZXR1cm4obGVuZ3RoKGdyZXAocGF0dGVybiwgbGlzdC5maWxlcyhkaXIpKSkgPiAwKQp9Cgpmb2xkZXJFeGlzdHNfd2lsZGNhcmQgPC0gZnVuY3Rpb24ocGF0dGVybiwgZGlyKSB7CiAgIyBjaGVjayBpZiB0aGVyZSBpcyBhbnkgZmlsZSBtYXRjaGluZyB0aGUgcGF0dGVybiAocmVnZXgpCiAgcmV0dXJuKGxlbmd0aChncmVwKHBhdHRlcm4sIGxpc3QuZGlycyhkaXIsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkpID4gMCkKfQpgYGAKCmBgYHtyIGdzZWFfY21kfQpydW5fZ3NlYSA8LSBmdW5jdGlvbihnc2VhX2phciwgcm5rLCBnbXgsIG5wZXJtLCBtYXhfdGVybXNpemUsIG1pbl90ZXJtc2l6ZSwgb3V0X2RpciwgcnB0X2xhYmVsKSB7CiAgY29tbWFuZCA8LSBwYXN0ZSgKICAgIGdzZWFfamFyLCAKICAgICJHU0VBUHJlUmFua2VkIC1nbXgiLCBnbXgsIAogICAgIi1ybmsiLCBybmssIAogICAgIi1ucGVybSIsIG5wZXJtLCAKICAgICItc2V0X21heCIsIG1heF90ZXJtc2l6ZSwgCiAgICAiLXNldF9taW4iLCBtaW5fdGVybXNpemUsIAogICAgIi1vdXQiLCBvdXRfZGlyLAogICAgIi1ycHRfbGFiZWwiLCBycHRfbGFiZWwsCiAgICAiPiBnc2VhX291dC50eHQiLAogICAgc2VwID0gIiAiKQogIGlmICghZm9sZGVyRXhpc3RzX3dpbGRjYXJkKHJwdF9sYWJlbCwgImdzZWFfb3V0IikpCiAgICBzeXN0ZW0oY29tbWFuZCkKICBlbHNlCiAgICBwcmludCgiR1NFQSByZXN1bHRzIGFscmVhZHkgZXhpc3RzOyByZW1vdmUgcHJldmlvdXMgcmVzdWx0IG9yIHVzZSBhIGRpZmZlcmVudCBqb2IgbmFtZSB0byBjb250aW51ZS4iKQp9CmBgYAoKYGBge3IgZ2V0X2dtdF9oZWxwZXJ9CmdldEdNVCA8LSBmdW5jdGlvbihzcmMsIHBhdHRlcm4pIHsKICBnbXRfdXJsIDwtIHNyYwoKICBmaWxlbmFtZXMgPSBnZXRVUkwoZ210X3VybCkKICB0ZXh0Q29ubiA9IHRleHRDb25uZWN0aW9uKGZpbGVuYW1lcykKICBjb250ZW50cyA9IHJlYWRMaW5lcyh0ZXh0Q29ubikKICBjbG9zZSh0ZXh0Q29ubikKICAKICAjIGZpbHRlciBvdXQgdGhlIGZpbGVuYW1lcyB1c2luZyB0aGUgcmVnZXggcGF0dGVybgogIHJ4ID0gZ3JlZ2V4cHIocGF0dGVybiwgY29udGVudHMsCiAgICAgICAgICAgICAgICBwZXJsID0gVFJVRSkKICAKICBnbXRfZmlsZSA8LSB1bmxpc3QocmVnbWF0Y2hlcyhjb250ZW50cywgcngpKQogIAogICMgZG93bmxvYWQgdGhlIGdtdCBmaWxlIGlmIHRoZXJlIGlzIG5vIGZpbGUgd2l0aCBleHRlbnNpb24gLmdtdCBpbiB0aGUgZ210IGZvbGRlcgogIGlmICghZmlsZUV4aXN0c193aWxkY2FyZCgiLmdtdCIsICJnbXQiKSkKICAgIGRvd25sb2FkLmZpbGUocGFzdGUoZ210X3VybCwgZ210X2ZpbGUsIHNlcCA9ICIiKSwgZGVzdGZpbGUgPSBmaWxlLnBhdGgoZ2V0d2QoKSwgImdtdCIsIGdtdF9maWxlKSkKfQpgYGAKCiMgTm9uLXRocmVzaG9sZGVkIEdlbmUgRW5yaWNobWVudCBBbmFseXNpcwoKIyMgQ3JlYXRlIFJhbmtlZCBMaXN0CgpUbyBwZXJmb3JtIGEgbm9uLXRocmVzaG9sZGVkIGdlbmUgZW5yaWNobWVudCBhbmFseXNpcywgd2UgdXNlIEdTRUEuIEJ1dCBiZWZvcmUgd2UgZG8gdGhhdCwgd2UgZmlyc3QgY3JlYXRlIGEgcmFua2VkIGxpc3QgdXNpbmcgdGhlIHNldCBvZiBhbGwgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIG9idGFpbmVkIGluIEFzc2lnbm1lbnQgMi4KCmBgYHtyIHJhbmtlZF9saXN0X2Rpc3BsYXlfb3JpZ2luYWx9CmRpZmZfZXhwX2xzdApgYGAKClJlY2FsbCB0aGF0IHJhbmsgY2FuIGJlIGNhbGN1bGF0ZWQgdXNpbmcgdGhlIGZvbGxvd2luZyBmb3JtdWxhCiQkClxtYXRocm17cmFua30gPSBcbWF0aHJte3NpZ259KFxtYXRocm17bG9nRkN9KSBcY2RvdCgtXGxvZ197MTB9cCkKJCQKCmBgYHtyIHJhbmtlZF9saXN0X2NyZWF0ZX0KIyBjYWxjdWxhdGUgcmFua3MKcmFua3MgPC0gc2lnbihkaWZmX2V4cF9sc3QkbG9nRkMpICogLWxvZzEwKGRpZmZfZXhwX2xzdCRQVmFsdWUpCgojIHN0b3JlIHRoZSByYW5rcyBhbG9uZyB3aXRoIGdlbmUgbmFtZXMKcmFua19saXN0X2dlbmVfbmFtZXMgPC0gZGlmZl9leHBfbHN0JGhnbmNfc3ltYm9sCnJhbmtfbGlzdCA8LSBjYmluZChyYW5rX2xpc3RfZ2VuZV9uYW1lcywgcmFua3MpCgojIHNvcnQgdGhlIHJhbmtlZCBsaXN0CnJhbmtfbGlzdCA8LSByYW5rX2xpc3Rbb3JkZXIoYXMubnVtZXJpYyhyYW5rX2xpc3RbLDJdKSwgZGVjcmVhc2luZyA9IFRSVUUpLCBdCmNvbG5hbWVzKHJhbmtfbGlzdCkgPC0gYygiR2VuZU5hbWUiLCAicmFuayIpCgojIHN0b3JlIHRoZSByYW5rZWQgbGlzdAp3cml0ZS50YWJsZShyYW5rX2xpc3QsIGZpbGUucGF0aChnZXR3ZCgpLCAiQ0JEX3ZzX1ZlaF9yYW5rcy5ybmsiKSwKICAgICAgICAgICAgY29sLm5hbWVzID0gVFJVRSwgc2VwID0gIlx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCgprYWJsZShoZWFkKHJhbmtfbGlzdCksIGNhcHRpb24gPSAiVGFibGUgMTogVG9wIGdlbmVzIGluIHRoZSByYW5rZWQgbGlzdCIpICU+JSBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKCJzdHJpcGVkIikKYGBgCgojIyBEb3dubG9hZCBHZW5lIFNldHMKCkZvciB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIHVzZSB0aGUgZ2VuZSBzZXRzIGF2YWlsYWJsZSBhdCBCYWRlcidzIExhYgoKYGBge3IgZ2V0X2dtdH0KZ2V0R01UKAogIHNyYyA9ICJodHRwOi8vZG93bmxvYWQuYmFkZXJsYWIub3JnL0VNX0dlbmVzZXRzL2N1cnJlbnRfcmVsZWFzZS9IdW1hbi9zeW1ib2wvIiwKICBwYXR0ZXJuID0gIig/PD08YSBocmVmPVwiKSguKi5HT0JQX0FsbFBhdGh3YXlzX25vX0dPX2llYS4qLikoLmdtdCkoPz1cIj4pIgopCmBgYAoKVGhlIGdlbmUgc2V0IHdlIHVzZWQgZm9yIHRoaXMgYW5hbHlzaXMgaXMgIkh1bWFuX0dPQlBfQWxsUGF0aHdheXNfbm9fR09faWVhX0FwcmlsXzAxXzIwMjJfc3ltYm9sLmdtdCIgZnJvbSBCYWRlcidzIGxhYi4gVGhlICJub19HT19pZWEiIHRhZyBpbiB0aGUgZmlsZSBuYW1lIGluZGljYXRlcyB0aGF0IHRoZSBnZW5lIHNldCBkb2VzIG5vdCBpbmNsdWRlIGdlbmVzIGluZmVycmVkIGZyb20gZWxlY3Ryb25pYyBhbm5vdGF0aW9uLgoKIyMgQW5hbHlzaXMgdXNpbmcgR1NFQQoKTmV4dCwgd2UgcnVuIEdTRUEgZnJvbSB0aGUgY29tbWFuZCBsaW5lLiBOb3RlIHRoYXQgdGhlIEdTRUEgamFyIGlzIHN0b3JlZCBhdCAiR1NFQV80LjIuNC8iLiBJZiB5b3UgaGF2ZSB0aGUgR1NFQSBqYXIgc3RvcmVkIGF0IGEgZGlmZmVyZW50IGxvY2F0aW9uLCBjaGFuZ2UgdGhlIGBnc2VhX2phcmAgcGFyYW1ldGVyIHRvIHBvaW50IHRvIHRoZSBjb3JyZWN0IGxvY2F0aW9uLgoKYGBge3IgcnVuX2dzZWF9CiMjIGZ1bmN0aW9uIHRoYXQgcmVwb3J0cyB0aGF0IEdTRUEgZG9lcyBub3QgZXhpc3RzIGFuZCB0ZXJtaW5hdGUgdGhlIGtuaXR0aW5nIG9mIHRoZSBjdXJyZW50IG5vdGVib29rCnJlcG9ydEdzZWFETkUgPC0gZnVuY3Rpb24oKSB7CiAgcHJpbnQoIkdTRUEgbm90IGZvdW5kIikKICBrbml0cjo6a25pdF9leGl0KCkKfQojIGNoZWNrIGlmIEdTRUEgZGlyZWN0b3J5IGV4aXN0cwppZiAoZm9sZGVyRXhpc3RzX3dpbGRjYXJkKCJHU0VBXyoiLCAifiIpKSB7CiAgIyBnZXQgdGhlIEdTRUEgaW5zdGFsbGF0aW9uICh2ZXJzaW9uIGluZGVwZW5kZW50KQogIGdzZWFfZGlyID0gbGlzdC5kaXJzKCJ+IiwgcmVjdXJzaXZlID0gRkFMU0UpW2dyZXAoIkdTRUFfKiIsIGxpc3QuZGlycygifiIsIHJlY3Vyc2l2ZSA9IEZBTFNFKSldCiAgaWYgKGxlbmd0aChnc2VhX2RpcikgPiAwKSB7CiAgICBnc2VhX3BhdGggPSBmaWxlLnBhdGgoZ3NlYV9kaXJbMV0sICJnc2VhLWNsaS5zaCIpCiAgICAjIGlmIHRoZSBzaGVsbCBzY3JpcHQgZXhpc3RzLCB0aGVuIGV4ZWN1dGUgR1NFQSBjb21tYW5kCiAgICBpZiAoZmlsZS5leGlzdHMoZ3NlYV9wYXRoKSkgewogICAgICBydW5fZ3NlYSgKICAgICAgICBnc2VhX2phciA9IGdzZWFfcGF0aCwKICAgICAgICBybmsgPSBmaWxlLnBhdGgoZ2V0d2QoKSwgIkNCRF92c19WZWhfcmFua3Mucm5rIiksCiAgICAgICAgZ214ID0gZmlsZS5wYXRoKGdldHdkKCksICJnbXQiLCAiSHVtYW5fR09CUF9BbGxQYXRod2F5c19ub19HT19pZWFfQXByaWxfMDFfMjAyMl9zeW1ib2wuZ210IiksCiAgICAgICAgbnBlcm0gPSAxMDAwLAogICAgICAgIG1heF90ZXJtc2l6ZSA9IDIwMCwKICAgICAgICBtaW5fdGVybXNpemUgPSAxNSwKICAgICAgICBvdXRfZGlyID0gZmlsZS5wYXRoKGdldHdkKCksICJnc2VhX291dCIpLAogICAgICAgIHJwdF9sYWJlbCA9ICJDQkRfdnNfVmVoX0dTRUFBbmFseXNpcyIpCiAgICB9CiAgICBlbHNlCiAgICAgIHJlcG9ydEdzZWFETkUoKQogIH0gZWxzZQogICAgcmVwb3J0R3NlYURORSgpCiAgCn0gZWxzZSB7CiAgcmVwb3J0R3NlYURORSgpCn0KYGBgCgpBZnRlciBydW5uaW5nIHRoZSBwcmV2aW91cyBibG9jayBzdWNjZXNzZnVsbHksIHdlIHdvdWxkIGhhdmUgdGhlIEdTRUEgcmVzdWx0IHN0b3JlZCBhdCB0aGUgZm9sZGVyIGBnc2VhX291dC9DQkRfdnNfVmVoX1ZTRUFBbmFseXNpcy5Hc2VhUHJlcmFua2VkLnh4eGAuIFdlIGNhbiBwdWxsIHRoZSByZXBvcnQgZm9yIHRoZSBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgY2xhc3Nlcy4KCmBgYHtyIGdldF9nc2VhX3Jlc3VsdH0KZ3NlYV9mb2xkZXJfbmFtZXMgPC0gbGlzdC5kaXJzKCJnc2VhX291dCIsIHJlY3Vyc2l2ZSA9IEZBTFNFKVtncmVwbCgiQ0JEX3ZzX1ZlaF9HU0VBQW5hbHlzaXMiLCBsaXN0LmRpcnMoImdzZWFfb3V0IiwgcmVjdXJzaXZlID0gRkFMU0UpKV0KZ3NlYV9mb2xkZXJfbmFtZSA8LSBnc2VhX2ZvbGRlcl9uYW1lc1sxXQpnc2VhX2pvYl9pZCA8LSB0YWlsKHN0cnNwbGl0KGdzZWFfZm9sZGVyX25hbWUsICJcXC4iKVtbMV1dLCBuID0gMSkKCmdzZWFfcG9zIDwtIHJlYWQuY3N2KGZpbGUucGF0aChnc2VhX2ZvbGRlcl9uYW1lLCBzcHJpbnRmKCJnc2VhX3JlcG9ydF9mb3JfbmFfcG9zXyVzLnRzdiIsIGdzZWFfam9iX2lkKSksIHNlcCA9ICJcdCIpCmdzZWFfbmVnIDwtIHJlYWQuY3N2KGZpbGUucGF0aChnc2VhX2ZvbGRlcl9uYW1lLCBzcHJpbnRmKCJnc2VhX3JlcG9ydF9mb3JfbmFfbmVnXyVzLnRzdiIsIGdzZWFfam9iX2lkKSksIHNlcCA9ICJcdCIpCmBgYAoKV2Ugd291bGQgbGlrZSB0byBwYXJzZSB0aGUgcm93cyBpbiB0aGUgR1NFQSByZXBvcnQgc28gdGhhdCBpdCBpcyBtb3JlIHJlYWRhYmxlLgoKYGBge3IgcGFyc2VfZ3NlYV9uYW1lX2NvbH0KIyBwYXJzZSB0aGUgTkFNRSBjb2x1bW4gaW4gR1NFQSBvdXRwdXQgKHNwbGl0IGJ5ICclJykKcGFyc2VHc2VhTmFtZSA8LSBmdW5jdGlvbihnc2VhX3RhYmxlKSB7CiAgc3BsaXR0ZWRfbmFtZXMgPSByZXNoYXBlMjo6Y29sc3BsaXQoZ3NlYV90YWJsZSROQU1FLCAnJScsIG5hbWVzID0gYygiZGVzY3JpcHRpb24iLCAnc3JjJywgJ2lkJykpCiAgcmV0dXJuKGNiaW5kKGdzZWFfdGFibGUsIHNwbGl0dGVkX25hbWVzKSkKfQoKZ3NlYV9wb3MgPC0gcGFyc2VHc2VhTmFtZShnc2VhX3BvcykKZ3NlYV9uZWcgPC0gcGFyc2VHc2VhTmFtZShnc2VhX25lZykKCmthYmxlKGhlYWQoZ3NlYV9wb3NbLGMoImRlc2NyaXB0aW9uIiwgInNyYyIsICJTSVpFIiwgIk5FUyIsICJFUyIpXSksIGNhcHRpb24gPSAiVGFibGUgMjogVG9wIHRlcm1zIG9mIHVwcmVndWFsdGVkIGdlbmVzIikgJT4lIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoInN0cmlwZWQiKQoKa2FibGUoaGVhZChnc2VhX25lZ1ssYygiZGVzY3JpcHRpb24iLCAic3JjIiwgIlNJWkUiLCAiTkVTIiwgIkVTIildKSwgY2FwdGlvbiA9ICJUYWJsZSAzOiBUb3AgdGVybXMgb2YgZG93bnJlZ3VsYXRlZCBnZW5lcyIpICU+JSBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKCJzdHJpcGVkIikKYGBgCldlIGFsc28gcHJlc2VudCB0aGUgZW5yaWNobWVudCBwbG90cyBmb3Igc29tZSBvZiB0aGUgdG9wIHRlcm1zIGFzc29jaWF0ZWQgd2l0aCB0aGUgdXByZWd1bGF0ZWQgZ2VuZXMuCgoKIVtGaWd1cmUgMTogRW5yaWNobWVudCBwbG90IGZvciAiVU5GT0xERUQgUFJPVEVJTiBSRVNQT05TRSIgZnJvbSBSZWFjdG9tZV0oZW5yaWNobWVudF9wbG90X1VQUi5wbmcpCgo8YnI+CgohW0ZpZ3VyZSAyOiBFbnJpY2htZW50IHBsb3QgZm9yICJSZXNwb25zZSB0byBFUiBzdHJlc3MiIGZyb20gR09CUF0oZW5yaWNobWVudF9wbG90X0VSU3RyZXNzLnBuZykKClRoZSB0b3AgdGVybXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB1cHJlZ3VsYXRlZCBnZW5lcyBhcmUgYWxsIHJlbGF0ZWQgdG8gRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCBtb3JlIGludGVyZXN0aW5nbHksIHVuZm9sZGVkIHByb3RlaW4gcmVzcG9uc2UuIEluIHBhcnRpY3VsYXIsIEVSQUQgKEVSIGFzc29jYWl0ZWQgcHJvdGVpbiBkZWdyYWRhdGlvbikgcGF0aHdheSBpcyBhbHNvIG9uZSBvZiB0aGUgdG9wIHRlcm1zLiBUaG9zZSBwYXRod2F5cyBhbmQgbWVjaGFuaXNtcyBhcmUgYWxzbyBkaXNjdXNzZWQgaW4gdGhlIGxpdGVyYXR1cmUuIFdlIHdpbGwgZXhwbG9yZSB0aG9zZSBwYXRod2F5IHVzaW5nIG5ldHdvcmsgYW5hbHlzaXMgaW4gdGhlIG5leHQgc2VjdGlvbi4KCiMjIERpc2N1c3Npb24KCjEuIEZvciB0aGlzIGFuYWx5c2lzLCBJIHVzZWQgR1NFQSB2ZXJzaW9uIDQuMi4zLiBJIHVzZWQgdGhlIEdTRUEgcHJlcmFua2VkIGFuYWx5c2lzIGluIEdTRUEuIFRoZSBnZW5lc2V0IHVzZWQgd2FzIG9idGFpbmVkIGZyb20gQmFkZXIncyBsYWIncyByZXBvc2l0b3J5LiBUaGUgY29kZSBmb3Igb2J0YWluaW5nIHRoZSBnZW5lc2V0IGlzIHNob3duIGFib3ZlLiBUaGUgZ2VuZXNldCBpcyBjcmVhdGVkIG9uIEFwcmlsIDEsIDIwMjIuIFRoZSBnZW5lc2V0IGlzIGN1cmF0ZWQgZnJvbSBHTywgR09CUCwgTVNpZ2RiLCBSZWFjdG9tZSwgV2lraVBhdGh3YXlzLCBOZXRQYXRoLCBQYW50aGVyLCBhbmQgSHVtYW5DeWMuCgoyLiBJbiB0aGUgZW5yaWNobWVudCByZXN1bHQsIHRoZSBwb3NpdGl2ZSBwaGVub3R5cGUgYXJlIHRoZSBzYW1wbGVzIHRyZWF0ZWQgd2l0aCBDQkQsIGFuZCB0aGUgbmVnYXRpdmUgcGhlbm90eXBlIGFyZSB0aGUgb25lcyB3aXRob3V0IENCRCB0cmVhdG1lbnQuIDEwNjQgLyAyMDU5IGdlbmUgc2V0cyBhcmUgdXByZWd1bGF0ZWQgaW4gdGhlIHBvc2l0aXZlIHNhbXBsZXMsIGFuZCA5OTUgLyAyMDU5IGdlbmUgc2V0cyBhcmUgdXByZWd1bGF0ZWQgaW4gdGhlIG5lZ2F0aXZlIHNhbXBsZXMuIEluIHRoZSBwb3NpdGl2ZSBwaGVub3R5cGUsIDIxNyBnZW5lIHNldHMgYXJlIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgYXQgbm9taW5hbCBwdmFsdWUgPCAxJTsgaW4gdGhlIG5lZ2F0aXZlIHBoZW5vdHlwZSwgMzQyIGdlbmUgc2V0cyBhcmUgc2lnbmlmaWNhbnRseSBlbnJpY2hlZCBhdCBub21pbmFsIHB2YWx1ZSA8IDElLiBUaGUgdG9wIHRlcm1zIGFzc29jaWF0ZWQgd2l0aCB0aGUgcG9zaXRpdmUgc2FtcGxlcyBhcmU6IFJFU1BPTlNFIFRPIEVORE9QTEFTTUlDIFJFVElDVUxVTSBTVFJFU1MgKEdPKSwgVU5GT0xERUQgUFJPVEVJTiBSRVNQT05TRSAoVVBSKSAoUmVhY3RvbWUpLCBJUkUxQUxQSEEgQUNUSVZBVEVTIENIQVBFUk9ORVMgKFJlYWN0b21lKS4gVGhlIHRvcCB0ZXJtcyBhc3NvY2lhdGVkIHdpdGggdGhlIG5lZ2F0aXZlIHNhbXBsZXMgYXJlOiBOVUNMRUFSIENIUk9NT1NPTUUgU0VHUkVHQVRJT04sIENIUk9NT1NPTUUgU0VHUkVHQVRJT04sIFNJU1RFUiBDSFJPTUFUSUQgU0VHUkVHQVRJT04sIGFsbCBmcm9tIEdPQlAuCgozLiBUaGUgcmVzdWx0cyBmcm9tIG5vbi10aHJlc2hvbGRlZCBhbmFseXNpcyB1c2luZyBHU0VBIGlzIHZlcnkgc2ltaWxhciB0byB0aGUgcmVzdWx0IG9idGFpbmVkIGZyb20gdGhlIHByZXZpb3VzIGFuYWx5c2lzIHVzaW5nIEc6cHJvZmlsZXIuIFRoZSB1cHJlZ3VsYXRlZCBnZW5lcyBhcmUgbW9zdGx5IHJlbGF0ZWQgdG8gRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCBwcm90ZWluIGRlZ3JhZGF0aW9uIHdoZXJlYXMgdGhlIGRvbndyZWd1bGF0ZWQgZ2VuZXMgYXJlIG1vc3RseSByZWxhdGVkIHRvIGNlbGwgY3ljbGUgcmVndWxhdGlvbiBhbmQgY2VsbCBkaXZpc2lvbnMuIEhvd2V2ZXIsIG92ZXJhbGwsIHRoZSB0ZXJtcyBmcm9tIHRoZSByZXN1bHRzIHVzaW5nIEdTRUEgaXMgbW9yZSBkaXZlcnNlLiBUaGlzIGlzIGJlY2F1c2UgR1NFQSBpcyBub3QgYSB0aHJlc2hvbGRlZCBtZXRob2QgYW5kIGl0IGdldHMgdG8gY29uc2lkZXIgYWxsIGdlbmVzIGluc3RlYWQgb2YganVzdCB0aG9zZSBwYXNzZWQgdGhlIHRocmVzaG9sZCBpbiB0aHJlc2hvbGRlZCBtZXRob2RzLiBBbHRob3VnaCB0aGUgdG9wIHRlcm1zIGFyZSBtb3N0bHkgdGhlIHNhbWUsIHRoaXMgaXMgbm90IGEgc3RyYWlnaHRmb3J3YXJkIGNvbXBhcmlzb24gYmVjYXVzZSB0aGUgdHdvIG1ldGhvZHMgKEdTRUEgdi5zLiBHOnByb2ZpbGVyKSB1c2VzIGRpZmZlcmVudCBhcHByb2FjaGVzLiBUaGUgc2ltaWxhcml0eSBpbiB0aGUgdGhlIHRvcCB0ZXJtcyBpcyBsaWtlbHkgYXR0cmlidXRlZCB0byB0aGUgc2lnbmlmaWNhbnQgb3ZlcnJlcHJlc2VudGF0aW9uIG9mIGNlcnRhaW4gZ2VuZXMuIFRoaXMgYWxzbyBnaXZlcyB1cyBzdHJvbmcgZXZpZGVuY2UgdG8gYmVsaWV2ZSB0aGF0IHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgYXJlIG1vcmUgbGlrZWx5IHRoYW4gbm90IHRvIGJlIGludm9sdmVkIGluIHRoZXNlIHBhdGh3YXlzLgoKIyBOZXR3b3JrIEFuYWx5c2lzIFVzaW5nIEN5dG9zY2FwZQoKIyMgQ3JlYXRpb24gb2YgRW5yaWNobWVudCBNYXAKCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBpbXBvcnQgdGhlIHJlc3VsdHMgZnJvbSBHU0VBIGludG8gQ3l0b3NjYXBlIGFuZCB2aXN1YWxpemUgdGhlIGVucmljaG1lbnQgcmVzdWx0cyBhcyBhIG5ldHdvcmsuIFRvIHRoaXMgZW5kLCB3ZSBmaXJzdCBuZWVkIHRvIGNyZWF0ZSBhIG5ldHdvcmsgYmFzZWQgb24gdGhlIGVucmljaG1lbnQgcmVzdWx0LiBXZSB1c2UgdGhlIEN5dG9zY2FwZSBwbHVnaW4gRW5yaWNobWVudE1hcCwgd2hpY2ggY2FuIGdlbmVyYXRlIGEgbmV0d29yayBmcm9tIEdTRUEgb3V0cHV0cy4KCldlIGNyZWF0ZWQgdGhlIGVucmljaG1lbnQgbWFwIGJ5IHVzaW5nIHRoZSBDeXRvc2NhcGUgR1VJLiBXZSBmaXJzdCBpbXBvcnRlZCB0aGUgR1NFQSBvdXRwdXQgZm9yIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSBwaGVub3R5cGVzLiBUaGVuLCB3ZSBpbXBvcnRlZCB0aGUgR01UIGZpbGUgYW5kIHJhbmtlZCBsaXN0IGZpbGUuIEZpbmFsbHksIHdlIGluc3BlY3RlZCBhbmQgY2hhbmdlZCB0aGUgcGFyYW1ldGVycyBmb3IgRW5yaWNobWVudCBtYXAuIFRoZSB0aHJlc2hvbGRzIGZvciBFbnJpY2htZW50TWFwIGFyZSBhcyBmb2xsb3dzOgoKLSBGRFIgcS12YWx1ZSBjdXRvZmY6IDAuMQotIHAtdmFsdWUgY3V0b2ZmOiAwLjA1Ci0gRWRnZSBjdXRvZmY6IDAuMzc1Ci0gRWRnZSBmaWx0ZXJpbmcgbWV0cmljOiBKYWNjYXJkK092ZXJsYXAgY29tYmluZWQKLSBQYXJzZSBiYWRlcmxhYiBuYW1lcyBpbiBHTVQgZmlsZTogVHJ1ZSAoZm9yIGJldHRlciByZWFkYWJpbGl0eSkKClJlY2FsbCB0aGF0IEphY2NhcmQgbWV0cmljIG1lYXN1cmVzIHRoZSBpbnRlcnNlY3Rpb24gb3ZlciB1bmlvbiB3aGVyZWFzIHRoZSBvdmVybGFwIG1ldHJpYyBtZWFzdXJlcyBpbnRlcnNlY3Rpb24gb3ZlciB0aGUgbWluaW11bSBzaXplLgoKVGhlIHJlc3VsdGluZyBuZXR3b3JrIGlzIHNob3duIGJlbG93OgoKIVtGaWd1cmUgMzogRW5yaWNobWVudCBtYXAgZ2VuZXJhdGVkIGZyb20gR1NFQSByZXN1bHQuIFBvc2l0aXZlIHBoZW5vdHlwZXMgKHVwcmVndWxhdGVkKSBhcmUgY29sb3JlZCByZWQgYW5kIG5lZ2F0aXZlIHBoZW5vdHlwZXMgKGRvd25yZWd1bGF0ZWQpIGFyZSBjb2xvcmVkIGJsdWUuXShhM2ZpZ3MvY3l0b3NjYXBlL25ldHdvcmtfb3ZlcnZpZXcucG5nKQoKQSB6b29tZWQgaW4gdmlldyBvZiB0aGUgY2x1c3RlciBvZiB0ZXJtcyBhc3NvY2lhdGVkIHdpdGggRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCB1bmZvbGRlZCBwcm90ZWluIHJlc3BvbnNlLiBUaGVzZSBhcmUgdGhlIGNsdXN0ZXJzIHRoYXQgd2Ugd2lsbCBmdXJ0aGVyIGludmVzdGlnYXRlLgoKIVtGaWd1cmUgNDogQSB6b29tZWQgaW4gdmlldyBvZiB0aGUgZW5yaWNobWVudCBtYXAgc2hvd2luZyB0aGUgY2x1c3RlciBjb250YWluaW5nIHRlcm1zIGFuZCBwYXRod2F5cyB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggRVIgc3RyZXNzIHJlc3BvbnNlIGFuZCB1bmZvbGRlZCBwcm90ZWluIHJlc3BvbnNlLiBUaG9zZSBhcmUgdGhlIHBhdGh3YXlzIHRoZSBhdXRob3JzIG9mIHRoZSBvcmlnaW5hbCBwYXBlciBwcm9wb3NlZCB0byBiZSByZWxhdGVkIHRvIENCRCdzIHJvbGUgaW4gaW5oaWJpdGluZyBTQVJTLUNvVi0yIHJlcGxpY2F0aW9uLl0oYTNmaWdzL2N5dG9zY2FwZS9uZXR3b3JrX3pvb21pbi5wbmcpCgohW0ZpZ3VyZSA1OiBBIHpvb21lZCBpbiB2aWV3IG9mIHRoZSBlbnJpY2htZW50IG1hcCBzaG93aW5nIHRoZSBjbHVzdGVyIGNvbnRhaW5pbmcgdGVybXMgYW5kIHBhdGh3YXlzIHRoYXQgYXJlIGFzc29jaWF0ZWQgd2l0aCBpbnRlcmZlcm9uIHJlc3BvbnNlcy4gVGhlIGF1dGhvcnMgb2YgdGhlIG9yaWdpbmFsIHB1YmxpY2F0aW9uIG1lbnRpb25lZCB0aGF0IHRoZXNlIHBhdGh3YXlzIGFzIGFuIGFsdGVybmF0aXZlIG1lY2hhbmlzbSBvZiBDQkQncyBpbmhpYml0aW9uIG9mIFNBUlMtQ29WLTIgcmVwbGljYXRpb24uIF0oYTNmaWdzL2N5dG9zY2FwZS9uZXR3b3JrX2ludGVyZmVyb25fem9vbWluLnBuZykKCiMjIE5ldHdvcmsgQW5ub3RhdGlvbgoKTmV4dCwgd2UgYW5ub3RhdGVkIHRoZSBuZXR3b3JrIHVzaW5nIHRoZSBwbHVnaW4gQXV0b0Fubm90YXRlLiBGb3IgQXV0b0Fubm9hdGUsIHdlIHVzZWQgdGhlIGRlZmF1bHQgcGFyYW1ldGVyOgotIExhYmVsaW5nIGFsZ29yaXRobTogV29yZENsb3VkIEFkamFjZW50IFdvcmQKLSBNYXggd29yZCBwZXIgbGFiZWw6IDMKLSBNaW4gd29yZCBvY2N1cnJlbmNlOiAxCi0gQWRqYWNlbnQgd29yZCBib251czogOAoKQWRkaXRpb25hbGx5LCB3ZSB0dXJuZWQgb24gdGhlIG9wdGlvbiAiTGF5b3V0IG5ldHdvcmsgdG8gcHJldmVudCBjbHVzdGVyIG92ZXJsYXAiIHNvIHRoYXQgdGhlIHJlc3VsdGluZyBhbm5vdGF0ZWQgbmV0d29yayBpcyBtb3JlIGNsZWFyIGFuZCBlYXN5LXRvLXJlYWQuCgpUaGUgcmVzdWx0aW5nIGFubm90YXRlZCBuZXR3b3JrIGlzIHNob3duIGJlbG93LgoKIVtGaWd1cmUgNjogQW5ub3RhdGVkIG5ldHdvcmsgb2YgdGhlIG9yaWdpbmFsIG5ldHdvcmsgc2hvd24gaW4gRmlndXJlIDUuIENsdXN0ZXJzIGFyZSByZS1sYXlvdXQgdG8gcHJldmVudCBvdmVybGFwIGFuZCBpbXByb3ZlIHJlYWRhYmlsaXR5Ll0oYTNmaWdzL2N5dG9zY2FwZS9uZXR3b3JrX2Fubm90YXRlZC5wbmcpCgojIyBTdW1tYXJ5IE5ldHdvcmsKCldlIGNvbGxhcHNlZCB0aGUgYW5ub3RhdGVkIG5ldHdvcmsgaW50byBhIHN1bW1hcnkgbmV0d29yayB1c2luZyB0aGUgYnVpbHQtaW4gZmVhdHVyZSBwcm92aWRlZCBieSBBdXRvQW5ub3RhdGUuCgohW0ZpZ3VyZSA3OiBTdW1tYXJ5IG5ldHdvcmsgd2l0aCB0aGUgYW5ub3RhdGlvbiBjbHVzdGVycyBjb2xsYXBzZWQuXShhM2ZpZ3MvY3l0b3NjYXBlL1N1bW1hcnlOZXR3b3JrLnBuZykKCiFbRmlndXJlIDg6IEEgem9vbWVkIGluIHZpZXcgb2YgdGhlIGNlbnRlciBvZiB0aGUgc3VtbWFyeSBuZXR3b3JrLiBUaGUgaGlnaGxpZ2h0ZWQgbm9kZXMgcmVwcmVzZW50IHRoZSBtYWluIHRoZW1lIG9mIHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuXShhM2ZpZ3MvY3l0b3NjYXBlL3N1bW1hcnlfbmV0X3pvb21pbi5wbmcpCgpUaGUgbWFqb3IgdGhlbWVzIGluIHRoZSBhbmFseXNpcyBhcmU6CgotIEVSIHN0cmVzcyAodXByZWd1bGF0ZWQpCi0gUHJvdGVpbiBkZWdyYWRhdGlvbiAodXByZWd1bGF0ZWQpCi0gSW1tdW5lIHJlc3BvbnNlICh1cHJlZ3VsYXRlZCkKLSBQcm90ZWluIGZvbGRpbmcgKHVwcmVndWxhdGVkKQotIENlbGwgY3ljbGUgKGRvd25yZWd1bGF0ZWQpCi0gRE5BIHJlcGFpciAoZG93bnJlZ3VsYXRlZCkKClRoZSB1cHJlZ3VsYXRlZCBwYXRod2F5cyBmaXQgdGhlIG1vZGVsIGFuZCBhZ3JlZSB3aXRoIHRoZSByZXN1bHRzIGJ5IHRoZSBhdXRob3JzIG9mIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbi4gVGhlIGF1dGhvcnMgZGlkIG5vdCBtZW50aW9uIHRvbyBtdWNoIGFib3V0IHRoZSBuZWdhdGl2ZWx5IHJlZ3VsYXRlZCBwYXRod2F5cy4gVGhleSBhcmUgbm90IG5lY2Vzc2FyaWx5IG5vdmVsIGJ1dCBub25ldGhlbGVzcyB3b3J0aCBmdXRoZXIgaW52ZXN0aWdhdGluZy4KCiMjIERpc2N1c3Npb24KCkRpc2N1c3Npb24gcXVlc3Rpb25lZCBhbnN3ZXJlZCBpbiB0aGUgcHJldmlvdXMgc3Vic2VjdGlvbnMuCgojIyBQdWJsaWNhdGlvbi1yZWFkeSBGaWd1cmUKCgoKIVtGaWd1cmUgOTogUHVibGljYXRpb24tcmVhZHkgZmlndXJlLiAoYSkgVGhlIGVudGlyZSBlbnJpY2htZW50IG1hcCwgZ2VuZXJhdGVkIHVzaW5nIHRoZSBFbnJpY2htZW50TWFwIHBsdWdpbiBpbiBDeXRvc2NhcGU7IChiKSBBIHpvb21lZC1pbiB2aWV3IG9mIHRoZSBlbnJpY2htZW50IG1hcCBzaG93aW5nIHBhdGh3YXlzIHJlbGF0aW5nIHRvIEVSIHN0cmVzcyByZXNwb25zZSBhbmQgdW5mb2xkZWQgcHJvdGVpbiByZXNwb25zZTsgKGMpIEEgY29sbGFwc2VkIHN1bW1hcnkgbmV0d29yazsgKGQpIEEgem9vbWVkLWluIHZpZXcgb2YgdGhlIHN1bW1hcnkgbmV0d29yayBoaWdobGlnaHRpbmcgdGhlIG1ham9yIHRoZW1lcy5dKGEzZmlncy9jeXRvc2NhcGUvbmV0d29ya19wdWJsaWNfZmlnLnBuZykKCihVbmZvcnR1bmF0ZWx5LCByZXNvbHV0aW9uIG9mIGZpZ3VyZXMgaXMgYSBsaXR0bGUgYml0IGxvdyBhbmQgdGhlIERQSSBvcHRpb24gZG9lcyBub3Qgc2VlbSB0byB3b3JrLiBQbGVhc2UgcmVmZXIgdG8gam91cm5hbCBmb3IgaGlnaGVyIHJlc29sdXRpb24gZmlndXJlcy4pCgojIEZpbmFsIERpc2N1c3Npb24KCjEuIFRoZSBlbnJpY2htZW50IHJlc3VsdHMgc3VwcG9yIHRoZSBjb25jbHVzaW9ucyBhbmQgbWVjaGFuaXNtIGRpc2N1c3NlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXIuIFRoZSByZXN1bHRzIGRvIG5vdCBkaWZmZXIgc2lnbmlmaWNhbnRseSBmcm9tIHRob3NlIGZyb20gQXNzaWdubWVudCAyLgoKMi4gVGhlIGludm9sdmVtZW50IG9mIHRoZSBnZW5lcyBpbiBFUiBzdHJlc3MgcmVzcG9uc2UgYW5kIHRoZSBtZWNoYW5pc20gb2YgdW5mb2xkZWQgcHJvdGVpbiByZXNwb25zZSBwYXRod2F5IGFyZSBkaXNjdXNzZWQgZXh0ZW5zaXZlbHkgaW4gKDIwMDgpIEVpemlyaWsgZXQgYWwuIGFuZCAoMjAwNSkgQ3JlZGxlIGV0IGFsLiBUaGUgbWVjaGFuaXNtIGRpc2N1c3NlZCBpbiB0aGVzZSBwYXBlcnMgYWxzbyBhZ3JlZSB3aXRoIHRoZSBwcm9wb3NlZCBtZWNoYW5pc20gb2YgQ0JEJ3MgYW50aXZpcmFsIGVmZmVjdCBkaXNjdXNzZWQgYnkgaW4gdGhlIG9yaWdpbmFsIHBhcGVyIGFuZCB0aGUgcmVzdWx0cyBvYnRhaW5lZCBpbiB0aGlzIGFuYWx5c2lzLgoKIyBBbmFseXNpcyBvZiBVUFIgUGF0aHdheQoKV2UgZnVydGhlciBpbnZlc3RpZ2F0ZSB0aGUgdW5mb2xkZWQgcHJvdGVpbiByZXNwb25zZSBwYXRod2F5LiBUaGUgcGF0aHdheSBpcyBvZiBwYXJ0aWN1bGFyIGludGVyZXN0IGJlY2F1c2UgdGhlIGF1dGhvcnMgcHJvcG9zZWQgdGhpcyBhcyB0aGUgcG90ZW50aWFsIG1lY2hhbmlzbSBmb3IgdGhlIGFudGl2aXJhbCBlZmZlY3Qgb2YgQ0JELiBUaGlzIHBhdGh3YXkgaXMgYXZhaWxhYmxlIG9uIFJlYWN0b21lLiBIZXJlIGlzIGEgZGV0YWlsZWQgcGF0aHdheSBkaWFncmFtIG9idGFpbmVkIGZyb20gUmVhY3RvbWUuCgohW0ZpZ3VyZSAxMDogUGF0aHdheSBkaWFncmFtIGZvciB0aGUgVW5mb2xkZWQgUHJvdGVpbiBSZXNwb25zZSBwYXRod2F5Ll0oYTNmaWdzL1VQUi5wbmcpCgpFeHBvcnQgdGhlIG5vcm1hbGl6ZWQgY291bnQgZmlsZSAod2l0aCBIR05DIHN5bWJvbCBhbm5vdGF0aW9uKSBmb3IgYW5ub3RhdGlvbiBvbiBSZWFjdG9tZSBwYXRod2F5IGRpYWdyYW0uCgpgYGB7ciBleHBvcnRfbm9ybWFsaXplZF9jb3VudF9hbm5vdGF0ZWR9CndyaXRlLmNzdihub3JtYWxpemVkX2NvdW50c19hbm5vdFszOjE0XSwgZmlsZSA9ICJub3JtYWxpemVkX2NvdW50X2Fubm90YXRlZC50eHQiKQp3cml0ZS5jc3YocWxmX2RpZmZfZXhwJHRhYmxlLCBmaWxlID0gInFsZl9kaWZmX2V4cC50eHQiKQpgYGAKClRoZSBleHByZXNzaW9uIGRhdGEgaXMgdXBsb2FkZWQgdG8gdGhlIG9ubGluZSBhbmFseXNpcyB0b29scyBwcm92aWRlZCBieSBSZWFjdG9tZS4gQmVsb3cgaXMgdGhlIHJlc3VsdGluZyBwYXRod2F5IGRpYWdyYW0gd2l0aCB0aGUgZ2VuZXMgaW4gdGhlIHBhdGh3YXkgY29sb3JlZCBiYXNlZCBvbiB0aGVpciBsZXZlbCBvZiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiAobG9nIEZDKS4gQXMgc2hvd24gaW4gdGhlIGZpZ3VyZSwgdGhlIG1ham9yaXR5IG9mIGdlbmVzIGluIHRoaXMgcGF0aHdheSBhcmUgdXByZWd1bGF0ZWQgYWx0aG91Z2ggYSBoYW5kZnVsIGFyZSBhbHNvIGRvd25yZWd1bGF0ZWQuIFVuZm9ydHVuYXRlbHksIHRoZSBidWlsdC1pbiB0b29sIGluIFJlYWN0b21lIGRvZXMgbm90IGFsbG93IHVzIHRvIGFubm90YXRlIHRoZSBwYXRod2F5IHdpdGggcC12YWx1ZSBvciB0aGUgYWN1dGFsIG51bWVyaWFsIGxvZ0ZDIHZhbHVlLgoKIVtGaWd1cmUgMTE6IFBhdGh3YXkgZGlhZ3JhbSBmb3IgdGhlIFVuZm9sZGVkIFByb3RlaW4gUmVzcG9uc2UgcGF0aHdheSB3aXRoIGdlbmVzIGluIHRoZSBwYXRod2F5IGNvbG9yLWNvZGVkIHRvIHJlZmxlY3QgdGhlIGxvZyBmb2xkIGNoYW5nZS5dKGEzZmlncy9VUFItY29sb3ItY29kZWQucG5nKQoKV2UgcmVwZWF0IGEgc2ltaWxhciBhbmFseXNpcyB1c2luZyBDeXRvc2NhcGUuIFRoaXMgdGltZSwgd2UgdXNlIHRoZSBleHByZXNzaW9uIGRhdGEgb2J0YWluZWQgaW4gQTIuIFRoaXMgZmlsZSBpbmNsdWRlcyBub3Qgb25seSB0aGUgbG9nRkMgYnV0IGFsc28gdGhlIHAtdmFsdWVzIGZvciBlYWNoIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lLiBBZnRlciBpbXBvcnRpbmcgdGhlIFJlYWN0b21lIHBhdGh3YXkgaW50byBDeXRvc2NhcGUsIHdlIHdyaXRlIGFuIGF1dG9tYXRpb24gc2NyaXB0IHRvIGFubm90YXRlIHRoZSBuZXR3b3JrIHVzaW5nIGxvZ0ZDIGFuZCBwLXZhbHVlczoKCmBgYHtyIHJlYWN0b21lX2Fubm90YXRlLCBldmFsPUZBTFNFfQpub2RlcyA8LSBSQ3kzOjpnZXRBbGxOb2RlcygpCmF0dHJpYl90YWJsZSA8LSBSQ3kzOjpnZXRUYWJsZUNvbHVtbnMoKQpmb3IgKG4gaW4gbm9kZXMpIHsKICBucG9zID0gUkN5Mzo6Z2V0Tm9kZVBvc2l0aW9uKG5vZGUubmFtZXMgPSBuKQogIGF0dHJpYiA9IGF0dHJpYl90YWJsZVthdHRyaWJfdGFibGUkbmFtZSA9PSBuLF0KICBpZiAoIWlzLm51bGwoYXR0cmliJGxvZ0ZDKSkgewogICAgUkN5Mzo6YWRkQW5ub3RhdGlvblRleHQodGV4dCA9IHNwcmludGYoImxvZ0ZDID0gJS4yZiIsIGF0dHJpYiRsb2dGQyksIHgucG9zID0gbnBvcyR4X2xvY2F0aW9uLCB5LnBvcyA9IG5wb3MkeV9sb2NhdGlvbikKICAgIFJDeTM6OmFkZEFubm90YXRpb25UZXh0KHRleHQgPSBzcHJpbnRmKCJwID0gJS4yZyIsIGF0dHJpYiRQVmFsdWUpLCB4LnBvcyA9IG5wb3MkeF9sb2NhdGlvbiwgeS5wb3MgPSBucG9zJHlfbG9jYXRpb24gKyAxMikKICB9Cn0KCmBgYAoKVGhpcyBzY3JpcHQgd2FzIHJ1biBvdXRzaWRlIHRoZSBub3RlYm9vay4gSXQgaXMgc2hvd24gaGVyZSBmb3IgZGVtb25zdHJhdGlvbiBwdXJwb3NlIG9ubHkuCgpUaGUgZmluYWwgYW5ub2F0ZWQgbmV0d29yayBpcyBhbm5vdGVkIHdpdGggbG9nRkMgYW5kIHAtdmFsdWVzLiBUaGUgY29sb3Igb2YgZWFjaCBub2RlIGNvcnJlc3BvbmRzIHRvIGxvZyBmb2xkIGNoYW5nZSAocmVkID0gdXByZWd1bGF0ZWQsIGJsdWUgPSBkb3ducmVndWxhdGVkKSBhbmQgdGhlIHNpemUgb2YgZWFjaCBub2RlIGlzIGludmVyc2UgcHJvcG9ydGlvbmFsIHRvIHRoZSBwLXZhbHVlIG9mIHRoZSBnZW5lIHJlcHJlc2VudGVkIGJ5IHRoZSBub2RlLgoKIVtGaWd1cmUgMTI6IEFubm90YXRlZCByZWFjdG9tZSBwYXRod2F5LiBUaGUgbGFyZ2VyIGEgbm9kZSwgdGhlIGxvd2VyIHRoZSBwLXZhbHVlLiBSZWQgY29ycmVzcG9uZHMgdG8gYSBoaWdoIGxvZ0ZDIHZhbHVlICh1cHJlZ3VsYXRlZCkgd2hlcmVhcyBibHVlIGNvcnJlc3BvbmRzIHRvIGEgbG93IChuZWdhdGl2ZSkgbG9nRkMgdmFsdWUgKGRvd25yZWd1bGF0ZWQpLl0oYTNmaWdzL2N5dG9zY2FwZS9yZWFjdG9tZV9hbm5vdGF0ZWQucG5nKQoKQXMgc2hvd24gaW4gdGhlIGZpZ3VyZSBhYm92ZSwgd2UgY2FuIHNlZSB0aGUgZ2VuZXMgaW52b2x2ZWQgaW4gdGhlIHVuZm9sZGVkIHByb3RlaW4gcmVzcG9uc2UgcGF0aHdheSBhcmUgbW9zdGx5IHNpZ25pZmljYW50bHkgdXByZWd1bGF0ZWQuIFRoaXMgaXMgY29uc2lzdGVudCB3aXRoIHRoZSBmaW5kaW5nIGluIHRoZSBvcmlnaW5hbCBwdWJsaWNhdGlvbi4gVGhlIGF1dGhvcnMgZnVydGhlciBjb25maXJtZWQgdGhpcyBieSBvYnNlcnZpbmcgdGhlIGVmZmVjdCBvbiBTQVJTLUNvVi0yIGluZmVjdGlvbiBpbiBjZWxscyB3aXRoIHRoZSBFUk4xIGdlbmUgKG9uZSBvZiB0aGUgZ2VuZSBpbnZvbHZlZCBpbiB0aGlzIHBhdGh3YXkpIGtub2NrZWQgb3V0LiBUaGVpciBleHBlcmltZW50IHNob3dzIHJlZHVjZWQgYW50aXZpcmFsIGVmZmVjdHMgZXZlbiB3aXRoIENCRCB0cmVhdG1lbnQgaW4gRVJOMSBrbm9ja291dCBjZWxscy4KCiMgSm91cm5hbAoKTGluayB0byBteSBqb3VybmFsIGVudHJ5IGZvciB0aGlzIGFzc2lnbm1lbnQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9iY2I0MjAtMjAyMi9LZXZpbl9HYW8vd2lraS9Bc3NpZ25tZW50LTMKCiMgUmVmZXJlbmNlCgpJc3NlcmxpbiwgUi4gKG4uZC4pLiBFbnJpY2htZW50IE1hcCBBbmFseXNpcyBQaXBlbGluZS4gQmFkZXIgTGFiIEdpdEh1Yi4KCkt1Y2VyYSwgTS4sIElzc2VybGluLCBSLiwgQXJraGFuZ29yb2Rza3ksIEEuLCAmIEJhZGVyLCBHLiBELiAoMjAxNikuIEF1dG9Bbm5vdGF0ZTogQSBDeXRvc2NhcGUgYXBwIGZvciBzdW1tYXJpemluZyBuZXR3b3JrcyB3aXRoIFNlbWFudGljIEFubm90YXRpb25zLiBGMTAwMFJlc2VhcmNoLCA1LCAxNzE3LiBodHRwczovL2RvaS5vcmcvMTAuMTI2ODgvZjEwMDByZXNlYXJjaC45MDkwLjEKCgpSZWltYW5kLCBKLiwgSXNzZXJsaW4sIFIuLCBWb2lzaW4sIFYuLCBLdWNlcmEsIE0uLCBUYW5udXMtTG9wZXMsIEMuLCBSb3N0YW1pYW5mYXIsIEEuLCBXYWRpLCBMLiwgTWV5ZXIsIE0uLCBXb25nLCBKLiwgWHUsIEMuLCBNZXJpY28sIEQuLCAmIEJhZGVyLCBHLiBELiAoMjAxOSkuIFBhdGh3YXkgZW5yaWNobWVudCBhbmFseXNpcyBhbmQgdmlzdWFsaXphdGlvbiBvZiBPTUlDUyBkYXRhIHVzaW5nIEc6UHJvZmlsZXIsIEdTRUEsIEN5dG9zY2FwZSBhbmQgRW5yaWNobWVudE1hcC4gTmF0dXJlIFByb3RvY29scywgMTQoMiksIDQ4MuKAkzUxNy4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvczQxNTk2LTAxOC0wMTAzLTkKCkNoZW4gWSwgTHVuIEFUTCwgU215dGggR0sgKDIwMTYpLiBGcm9tIHJlYWRzIHRvIGdlbmVzIHRvIHBhdGh3YXlzOiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBvZiBSTkEtU2VxIGV4cGVyaW1lbnRzIHVzaW5nIFJzdWJyZWFkIGFuZCB0aGUgZWRnZVIgcXVhc2ktbGlrZWxpaG9vZCBwaXBlbGluZS4gRjEwMDBSZXNlYXJjaCA1LCAxNDM4CgpEdXJpbmNrLCBTLiwgU3BlbGxtYW4sIFAuIFQuLCBCaXJuZXksIEUuLCAmIEh1YmVyLCBXLiAoMjAwOSkuIE1hcHBpbmcgaWRlbnRpZmllcnMgZm9yIHRoZSBpbnRlZ3JhdGlvbiBvZiBnZW5vbWljIGRhdGFzZXRzIHdpdGggdGhlIFIvQmlvY29uZHVjdG9yIHBhY2thZ2UgYmlvbWFSdC4gTmF0dXJlIC0gcHJvdG9jb2xzLCA0KDgpLCAxMTg04oCTMTE5MS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbnByb3QuMjAwOS45NwpNYXJ0aW4gTW9yZ2FuICgyMDIxKS4gQmlvY01hbmFnZXI6IEFjY2VzcyB0aGUgQmlvY29uZHVjdG9yIFByb2plY3QgUGFja2FnZSBSZXBvc2l0b3J5LiBSIHBhY2thZ2UgdmVyc2lvbiAxLjMwLjE2LiBodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPUJpb2NNYW5hZ2VyCgpNY0NhcnRoeSBESiwgQ2hlbiBZIGFuZCBTbXl0aCBHSyAoMjAxMikuIERpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIG9mIG11bHRpZmFjdG9yIFJOQS1TZXEgZXhwZXJpbWVudHMgd2l0aCByZXNwZWN0IHRvIGJpb2xvZ2ljYWwgdmFyaWF0aW9uLiBOdWNsZWljIEFjaWRzIFJlc2VhcmNoIDQwLCA0Mjg4LTQyOTcKCk5ndXllbiwgTC4gQy4sIFlhbmcsIEQuLCBOaWNvbGFlc2N1LCBWLiwgQmVzdCwgVC4gSi4sIE9odHN1a2ksIFQuLCBDaGVuLCBTLi1OLiwgRnJpZXNlbiwgSi4gQi4sIERyYXltYW4sIE4uLCBNb2hhbWVkLCBBLiwgRGFubiwgQy4sIFNpbHZhLCBELiwgR3VsYSwgSC4sIEpvbmVzLCBLLiBBLiwgTWlsbGlzLCBKLiBNLiwgRGlja2luc29uLCBCLiBDLiwgVGF5LCBTLiwgT2FrZXMsIFMuIEEuLCBQYXVsaSwgRy4gRi4sIE1lbHR6ZXIsIEQuIE8uLCDigKYgUm9zbmVyLCBNLiBSLiAoMjAyMSkuIENhbm5hYmlkaW9sIGluaGliaXRzIFNBUlMtQ09WLTIgcmVwbGljYXRpb24gYW5kIHByb21vdGVzIHRoZSBob3N0IGlubmF0ZSBpbW11bmUgcmVzcG9uc2UuIFNjaWVuY2UgQWR2YW5jZXMuIGh0dHBzOi8vd3d3LnNjaWVuY2Uub3JnL2RvaS9hYnMvMTAuMTEyNi9zY2lhZHYuYWJpNjExMApSb2JpbnNvbiBNRCwgTWNDYXJ0aHkgREogYW5kIFNteXRoIEdLICgyMDEwKS4gZWRnZVI6IGEgQmlvY29uZHVjdG9yIHBhY2thZ2UgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIG9mIGRpZ2l0YWwgZ2VuZSBleHByZXNzaW9uIGRhdGEuIEJpb2luZm9ybWF0aWNzIDI2LCAxMzktMTQwCgpHdSwgWi4gKDIwMTYpIENvbXBsZXggaGVhdG1hcHMgcmV2ZWFsIHBhdHRlcm5zIGFuZCBjb3JyZWxhdGlvbnMgaW4gbXVsdGlkaW1lbnNpb25hbCBnZW5vbWljIGRhdGEuIEJpb2luZm9ybWF0aWNzLgoKS29sYmVyZyBMLCBSYXVkdmVyZSBVLCBLdXptaW4gSSwgVmlsbyBKLCBQZXRlcnNvbiBIICgyMDIwKS4g4oCcZ3Byb2ZpbGVyMi0gYW4gUiBwYWNrYWdlIGZvciBnZW5lIGxpc3QgZnVuY3Rpb25hbCBlbnJpY2htZW50IGFuYWx5c2lzIGFuZCBuYW1lc3BhY2UgY29udmVyc2lvbiB0b29sc2V0IGc6UHJvZmlsZXIu4oCdIEYxMDAwUmVzZWFyY2gsIDkgKEVMSVhJUikoNzA5KS4gUiBwYWNrYWdlIHZlcnNpb24gMC4yLjEuCgpTdGVmYW4gTWlsdG9uIEJhY2hlIGFuZCBIYWRsZXkgV2lja2hhbSAoMjAyMCkuIG1hZ3JpdHRyOiBBIEZvcndhcmQtUGlwZSBPcGVyYXRvciBmb3IgUi4gaHR0cHM6Ly9tYWdyaXR0ci50aWR5dmVyc2Uub3JnLCBodHRwczovL2dpdGh1Yi5jb20vdGlkeXZlcnNlL21hZ3JpdHRyLgp2YW4gQnJlZW1lbiwgUi4gQi4sIE11Y2hpcmksIFIuIE4uLCBCYXRlcywgVC4gQS4sIFdlaW5zdGVpbiwgSi4gQi4sIExlaWVyLCBILiBDLiwgRmFybGV5LCBTLiwgJiBUYWZlc3NlLCBGLiBHLiAoMjAyMikuIAoKQ2FubmFiaW5vaWRzIEJsb2NrIENlbGx1bGFyIEVudHJ5IG9mIFNBUlMtQ29WLTIgYW5kIHRoZSBFbWVyZ2luZyBWYXJpYW50cy4gSm91cm5hbCBvZiBuYXR1cmFsIHByb2R1Y3RzLCA4NSgxKSwgMTc24oCTMTg0LiBodHRwczovL2RvaS5vcmcvMTAuMTAyMS9hY3Muam5hdHByb2QuMWMwMDk0NgoKRmFicmVnYXQgQSwgU2lkaXJvcG91bG9zIEssIFZpdGVyaSBHLCBNYXJpbi1HYXJjaWEgUCwgUGluZyBQLCBTdGVpbiBMLCBEJ0V1c3RhY2hpbyBQLCBIZXJtamFrb2IgSC4gUmVhY3RvbWUgZGlhZ3JhbSB2aWV3ZXI6IGRhdGEgc3RydWN0dXJlcyBhbmQgc3RyYXRlZ2llcyB0byBib29zdCBwZXJmb3JtYW5jZS4gQmlvaW5mb3JtYXRpY3MgKE94Zm9yZCwgRW5nbGFuZCkuIDIwMTggQXByOzM0KDcpIDEyMDgtMTIxNC4gZG9pOiAxMC4xMDkzL2Jpb2luZm9ybWF0aWNzL2J0eDc1Mi4gUHViTWVkIFBNSUQ6IDI5MTg2MzUxLiBQdWJNZWQgQ2VudHJhbCBQTUNJRDogUE1DNjAzMDgyNi4KCkVpemlyaWssIEQuIEwuLCBDYXJkb3pvLCBBLiBLLiwgJiBDbm9wLCBNLiAoMjAwOCkuIFRoZSByb2xlIGZvciBlbmRvcGxhc21pYyByZXRpY3VsdW0gc3RyZXNzIGluIGRpYWJldGVzIG1lbGxpdHVzLiBFbmRvY3JpbmUgcmV2aWV3cywgMjkoMSksIDQy4oCTNjEuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMjEwL2VyLjIwMDctMDAxNQoKQ3JlZGxlLCBKLiBKLiwgRmluZXItTW9vcmUsIEouIFMuLCBQYXBhLCBGLiBSLiwgU3Ryb3VkLCBSLiBNLiwgJiBXYWx0ZXIsIFAuICgyMDA1KS4gT24gdGhlIG1lY2hhbmlzbSBvZiBzZW5zaW5nIHVuZm9sZGVkIHByb3RlaW4gaW4gdGhlIGVuZG9wbGFzbWljIHJldGljdWx1bS4gUHJvY2VlZGluZ3Mgb2YgdGhlIE5hdGlvbmFsIEFjYWRlbXkgb2YgU2NpZW5jZXMgb2YgdGhlIFVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSwgMTAyKDUyKSwgMTg3NzPigJMxODc4NC4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwNzMvcG5hcy4wNTA5NDg3MTAyCg==